#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "MSTK.h"
#include <mpi.h>

int main(int argc, char *argv[]) {
  int i, ok;
  char mname[256],filename[256];
  char buf[256];
  char subfilename[256];
  Mesh_ptr mesh, recv_mesh, *submeshes;
  RepType rtype;
  /* default divide into two parts */
  int num = 3;
  int rank;

  /* command line parameter */
  MPI_Init(&argc,&argv);
  MPI_Comm_size(MPI_COMM_WORLD,&num);
  MPI_Comm_rank(MPI_COMM_WORLD,&rank);
  printf ("Number of tasks= %d My rank= %d\n", num,rank);

  

  /* initialize MPI data type */
  MESH_InitializeMPI(num);


  /* Build the global attributes list */
  char attname[256];
  MAttrib_ptr attrib;
  List_ptr attrib_list = List_New(2);
  strcpy(attname,"coordinates");
  attrib = MAttrib_New(NULL,attname,VECTOR,MVERTEX,3);
  List_Add(attrib_list,attrib);

  strcpy(attname,"Face_PType");
  attrib = MAttrib_New(NULL,attname,INT,MFACE);
  List_Add(attrib_list,attrib);


  /* Load the mesh */
  strcpy(mname,"mesh/pig");
  strcpy(filename,mname);
  strcat(filename,".mstk");
    
  /* master process read in and divide the mesh */
  if(rank == 0) { 
    /* Initialize MSTK - Always do this even if it does not seem to
    matter in this version of MSTK */
    MSTK_Init();  
    mesh = MESH_New(UNKNOWN_REP);
    ok = MESH_InitFromFile(mesh,filename);
    if (!ok) {
      fprintf(stderr,"Cannot open input file %s\n\n\n",filename);
      exit(-1);
    }
    fprintf(stdout,"mstk mesh %s read in successfully\n",filename);
    
    /* add coordinates as attributes */
    MESH_InitializeAttr(mesh,attrib_list);
    MESH_AttrCoord(mesh,0);


    /* Partition the mesh*/
    rtype = MESH_RepType(mesh);
    submeshes = (Mesh_ptr *)MSTK_malloc((num)*sizeof(Mesh_ptr));
    ok = MESH_Partition(mesh,submeshes,(num));
    fprintf(stdout,"%s has been partitioned into %d submeshes\n",filename,num);
    
    
    /* send the mesh */
    for (i = 0 ; i < num-1 ; i++) {
      /* initialze attributes*/
      MESH_InitializeAttr(submeshes[i],attrib_list);

      strcpy(subfilename,mname);
      itoa(i+1,buf);
      strcat(subfilename,buf);
      strcat(subfilename,".mstk");
      MESH_WriteToFile(submeshes[i],subfilename,rtype);
      /* built ptype */
      MESH_BuildPType(mesh,submeshes[i]);
      /* add ghost */
      MESH_AddGhost(mesh,submeshes[i],1);
      /* add ptype into attributes for debugging*/
      MESH_Surf_AttrPType(submeshes[i],1);
      /* copy coordinates attribute */
      MESH_CopyAttr(mesh,submeshes[i],0);

      /* write regular mstk mesh */
      strcpy(subfilename,mname);
      itoa(i+1,buf);
      strcat(subfilename,buf);
      strcat(subfilename,"-add-ghost.mstk");
      MESH_WriteToFile(submeshes[i],subfilename,rtype);
      fprintf(stdout,"submesh %d has been written into %s\n",i+1,subfilename);
      /* write parallel mstk mesh */
      strcpy(subfilename,mname);
      itoa(i+1,buf);
      strcat(subfilename,buf);
      strcat(subfilename,"-P-add-ghost.mstk");
      PMESH_WriteToFile(submeshes[i],subfilename,R1);
      fprintf(stdout,"parallel submesh %d has been written into %s\n",i+1,subfilename);
      /* send the mesh */
      MESH_SendMesh(submeshes[i],i+1,MPI_COMM_WORLD);
      /* send attribute */
      MESH_SendAttr(submeshes[i], 0, i+1, MPI_COMM_WORLD);
      MESH_SendAttr(submeshes[i], 1, i+1, MPI_COMM_WORLD);
    }
  }

  if(rank != 0) {
    /* receive mesh */
    recv_mesh = MESH_New(R1);
    fprintf(stdout,"begin receive submesh %d \n",rank);
    MESH_RecvMesh(recv_mesh,2,0,rank,MPI_COMM_WORLD);
    fprintf(stdout,"submesh %d received\n",rank);
    /* initialze attributes*/
    MESH_InitializeAttr(recv_mesh,attrib_list);
    /* receive attributes */
    MESH_RecvAttr(recv_mesh, 0, 0, rank, MPI_COMM_WORLD);
    MESH_RecvAttr(recv_mesh, 1, 0, rank, MPI_COMM_WORLD);
    strcpy(filename,"pmesh");
    itoa(rank,buf);
    strcat(filename,buf);
    strcat(filename,".mstk");

    PMESH_WriteToFile(recv_mesh,filename,R1);
    fprintf(stdout,"parallel mesh %d has been written\n",rank);

  
  }
 
  if(rank == 0) {
    /* Deleting of mesh is not necessary if this the end of the program */
    for (i = 0; i < num-1; i++)
      MESH_Delete(submeshes[i]);
    /* Write out a copy of the mesh */
    strcpy(filename,mname);
    strcat(filename,"-copy.mstk");
    MESH_WriteToFile(mesh,filename,rtype);

  }
 
  MESH_FinalizeMPI();
  MPI_Finalize();
  return 1;
}

